package com.codefish.framework.spring.context.support;

import com.codefish.framework.spring.beans.annotation.AutowiredAnnotationBeanPostProcessor;
import com.codefish.framework.spring.beans.exception.BeansException;
import com.codefish.framework.spring.beans.exception.NoSuchBeanDefinitionException;
import com.codefish.framework.spring.beans.factory.config.IBeanFactoryPostProcessor;
import com.codefish.framework.spring.beans.factory.config.IBeanPostProcessor;
import com.codefish.framework.spring.beans.factory.config.IConfigurableListableBeanFactory;
import com.codefish.framework.spring.context.ApplicationEvent;
import com.codefish.framework.spring.context.IConfigurableApplicationContext;
import com.codefish.framework.spring.context.event.*;
import com.codefish.framework.spring.core.io.DefaultResourceLoader;
import com.codefish.framework.spring.core.utils.AssertUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 抽象的ApplicationContext
 *
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/10/04 上午 10:00
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements IConfigurableApplicationContext {

    /**
     * beanFactoryPostProcessor列表
     */
    private final List<IBeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private Thread shutdownHook;
    /**
     * 事件广播器
     */
    private IApplicationEventMulticaster applicationEventMulticaster;
    /**
     * 事件监听者列表
     */
    private final Set<IApplicationListener<?>> applicationListeners = new HashSet<>();

    public AbstractApplicationContext() {
        //注册销毁生命周期钩子
        registerShutdownHook();
    }

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        //初始化并获得beanFactory
        IConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        //为beanFactory做一些前置操作
        prePareBeanFactory(beanFactory);
        // 允许子类重写该方法，从而实现对beanFactory做一些后置操作
        postProcessBeanFactory(beanFactory);
        // 执行所有和beanFactory绑定的BeanFactoryPostProcessors
        invokeBeanFactoryPostProcessors(beanFactory);
        // 向beanFactory注册BeanPostProcessor
        registerBeanPostProcessors(beanFactory);
        //初始化事件广播器
        initApplicationEventMulticaster();
        //注册监听者
        registerListeners();
        //实例化所有单例的且非lazy-int的bean
        finishBeanFactoryInitialization(beanFactory);
        //完成refresh操作
        finishRefresh();
    }

    /**
     * 初始化beanFactory并返回beanFactory
     *
     * @return beanFactory实例
     */
    protected IConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }

    /**
     * 为beanFactory做一些前置操作
     */
    protected void prePareBeanFactory(IConfigurableListableBeanFactory beanFactory) {
        //配置context相关Aware
        beanFactory.addBeanPostProcessor(new ApplicationAwarePostProcessor(this));
        //添加ApplicationListenerDetector，实现自动注册监听者bean实例到广播器中
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
        //添加AutowiredAnnotationBeanPostProcessor，实现对bean的基于注解的依赖注入
        beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor(getBeanFactory()));
    }

    /**
     * 对beanFactory做后置操作
     *
     * @param beanFactory 目标beanFactory
     */
    protected void postProcessBeanFactory(IConfigurableListableBeanFactory beanFactory) {
        //不做任何事，由子类来重写...
    }

    /**
     * 执行所有和beanFactory绑定的BeanFactoryPostProcessors
     *
     * @param beanFactory 目标beanFactory
     */
    protected void invokeBeanFactoryPostProcessors(IConfigurableListableBeanFactory beanFactory) {
        for (IBeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {
            postProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * 向beanFactory注册BeanPostProcessor
     *
     * @param beanFactory 目标beanFactory
     */
    protected void registerBeanPostProcessors(IConfigurableListableBeanFactory beanFactory) {
        //从beanFactory中获取所有类型为IBeanFactoryPostProcessor的beanName
        List<String> ppBeanNames = beanFactory.getBeanNamesForType(IBeanPostProcessor.class);
        for (String ppBeanName : ppBeanNames) {
            IBeanPostProcessor beanPostProcessor = beanFactory.getBean(ppBeanName, IBeanPostProcessor.class);
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    /**
     * 初始化事件广播器
     */
    protected void initApplicationEventMulticaster() {
        //尝试从容器中获取可用的caster
        IApplicationEventMulticaster casterBean;
        try {
            casterBean = getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, IApplicationEventMulticaster.class);
        } catch (Exception e) {
            //如果不存在则创建一个SimpleApplicationEventMulticaster
            casterBean = new SimpleApplicationEventMulticaster();
        }

        this.applicationEventMulticaster = casterBean;
    }

    /**
     * 注册监听者
     */
    protected void registerListeners() {
        for (IApplicationListener<?> applicationListener : this.applicationListeners) {
            getApplicationEventMulticaster().addApplicationListener(applicationListener);
        }
    }

    /**
     * 完成beanFactory的初始化工作
     */
    protected void finishBeanFactoryInitialization(IConfigurableListableBeanFactory beanFactory) {
        //预先加载单例的非lazy-init的bean
        beanFactory.preInstantiateSingletons();
    }

    /**
     * 完成上下文的刷新操作
     */
    protected void finishRefresh() {
        //发布完成上下文刷新事件
        getApplicationEventMulticaster().multicastEvent(new ContextRefreshEvent(this));
    }


    protected IApplicationEventMulticaster getApplicationEventMulticaster() {
        return this.applicationEventMulticaster;
    }

    @Override
    public void addBeanFactoryPostProcessor(IBeanFactoryPostProcessor postProcessor) {
        AssertUtils.notNull(postProcessor, "BeanFactoryPostProcessor不能为空");
        this.beanFactoryPostProcessors.add(postProcessor);
    }

    public List<IBeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
        return this.beanFactoryPostProcessors;
    }

    @Override
    public void registerShutdownHook() {
        if (this.shutdownHook == null) {
            this.shutdownHook = new Thread(() -> {
                doClose();
            }, SHUTDOWN_HOOK_THREAD_NAME);
            Runtime.getRuntime().addShutdownHook(this.shutdownHook);
        }
    }

    @Override
    public void addApplicationListener(IApplicationListener<?> applicationListener) {
        if (this.applicationEventMulticaster != null) {
            this.applicationEventMulticaster.addApplicationListener(applicationListener);
        }
        this.applicationListeners.add(applicationListener);
    }

    @Override
    public void close() {
        doClose();
        if (this.shutdownHook != null) {
            Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
        }
    }

    protected void doClose() {
        //发布容器关闭事件
        publishEvent(new ContextClosedEvent(this));
        //清除一些缓存
        this.applicationListeners.clear();
        //销毁beanFactory中的所有bean
        getBeanFactory().destroySingletons();
        //关闭beanFactory
        closeBeanFactory();
    }

    // ------------------------------------------
    // ---  以下方法实现IListableBeanFactory接口----
    //-------------------------------------------

    @Override
    public Object getBean(String beanName) throws NoSuchBeanDefinitionException {
        return getBeanFactory().getBean(beanName);
    }

    @Override
    public <T> T getBean(String beanName, Class<T> requiredType) throws NoSuchBeanDefinitionException {
        return getBeanFactory().getBean(beanName, requiredType);
    }

    @Override
    public List<String> getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public List<String> getBeanNamesForType(Class<?> type) {
        return getBeanFactory().getBeanNamesForType(type);
    }


    // ------------------------------------------------
    // ---  以下方法实现IApplicationEventPublisher接口----
    // ------------------------------------------------

    @Override
    public void publishEvent(ApplicationEvent applicationEvent) {
        getApplicationEventMulticaster().multicastEvent(applicationEvent);
    }


    // -------------------------
    // ---  以下方法由子类实现 ----
    //--------------------------

    /**
     * 从资源文件(如xml)加载beanFactory
     *
     * @throws BeansException
     * @throws IllegalStateException
     */
    protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

    /**
     * 关闭beanFactory
     */
    protected abstract void closeBeanFactory();


    @Override
    public abstract IConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

}
